#pragma once
#include "sock.hpp"
#include <iostream>
#include <functional>
#include <poll.h>
#include <string>

namespace poll_ns
{
    using func_t = std::function<std::string(const std::string &)>;

    const static int defaultPort = 8080;
    const static int defaultfd = -1; // 操作系统不会关心小于0的文件描述符，因为文件描述符表中数组下标是从0开始的
    const static int num = 2048;
    class pollServer
    {
    public:
        pollServer(func_t func, int port = defaultPort)
            : _port(port), _listensock(-1), _rfds(nullptr), _func(func)
        {
            // logMessage(DEBUG, "%d", _port);
        }
        void initServer()
        {
            _listensock = Sock::Socket();
            Sock::Bind(_listensock, _port);
            Sock::Listen(_listensock);
            _rfds = new struct pollfd[num]; // 这个数组我们可以搞成扩容版的，比如用vector来存储结构体，但今天我们就直接写成固定的了
            for (int i = 0; i < num; i++)
            {
                ResetItem(i);
            }
            _rfds[0].fd = _listensock; // 服务器的第一个套接字一定是listensock
            _rfds[0].events = POLLIN;  // 直接把宏的值赋值给events即可，events最高比特位为1时，对应的宏大小为32768
        }
        void Print()
        {
            std::cout << "fd_list: ";
            for (int i = 0; i < num; i++)
            {
                if (_rfds[i].fd != defaultfd)
                    std::cout << _rfds[i].fd << " ";
            }
            std::cout << "\n";
        }
        void ResetItem(int i)
        {
            _rfds[i].fd = defaultfd;
            _rfds[i].events = 0;
            _rfds[i].revents = 0;
        }
        void Accepter(int listensock)
        {
            // 走到这里，accept调用时，一定不会发生阻塞，因为listensock读事件已经就绪了，数据拷贝的条件已经满足了
            std::string clientip;
            uint16_t clientport;
            int sock = Sock::Accept(listensock, &clientip, &clientport);
            if (sock < 0)
                return;
            logMessage(NORMAL, "accept success [%s:%d]", clientip.c_str(), clientport);

            // 1.将新的sock托管给poll监视
            int i = 0;
            for (; i < num; i++)
            {
                if (_rfds[i].fd != defaultfd)
                    continue;
                break;
            }
            // 跳出循环有两种情况，一种是遇到非法fd的位置了，一种是数组的下标全都有合法的fd，fd已经满了
            if (i == num)
            {
                logMessage(WARNING, "server is full, please wait...");
                close(sock);
                // 服务器压力很大了，不能处理已经三次握手后的连接了，对不起，我服务器要发起四次挥手了，我要和你断开连接，你要是还想访问，那就下一次再试试，
                // 看看下一次服务器能不能处理完成一些连接，好空余出新的fd位置供你使用，下次你再来吧
            }
            else
            {
                _rfds[i].fd = sock;
                _rfds[i].events = POLLIN;
                _rfds[i].revents = 0; // 稳妥起见（但其实在初始化该数组的时候我们就已经做过初始化为0的工作了）
            }
            Print();
        }
        void Recver(int pos)
        {

            char buffer[1024];
            ssize_t s = recv(_rfds[pos].fd, buffer, sizeof(buffer) - 1, 0); // 设置为0表示没有特殊的标志选项，仅仅以默认方式接收数据就行
            if (s > 0)
            {
                buffer[s] = 0;
                logMessage(NORMAL, "client# %s", buffer);
            }
            else if (s == 0)
            {
                close(_rfds[pos].fd);
                ResetItem(pos);
                logMessage(NORMAL, "client quit !");
                // 既然对方已经退出了，那服务器就没有必要关心这个fd了，select不应该再继续监视该文件描述符了
                return;
            }
            else
            {
                // 读取数据失败了，那也将fd关闭掉，从数组中去除fd
                close(_rfds[pos].fd);
                ResetItem(pos);
                logMessage(ERROR, "client quit: %s", strerror(errno));
                return;
            }
            // 2.处理request
            std::string response = _func(buffer); // string (const char* s);string的构造函数重载
            // 3.返回response
            // write 今天直接写了，我们不想再添加wfds了，后面讲epoll的时候会把所有的问题都解决掉
            write(_rfds[pos].fd, response.c_str(), response.size());
        }
        void HandlerReadEvent()
        {
            // 1.handler event rfds中，不仅仅只有一个fd是就绪的，可能存在多个
            // 2.目前select只处理了fd的读事件
            for (int i = 0; i < num; i++)
            {
                if (_rfds[i].fd == defaultfd)
                    continue; // 过滤掉非法的fd

                // 但合法的fd不一定是就绪的，很有可能是刚刚才添加到_fdarray数组里面的，还没来得及返回到start托管给poll呢

                // 我们需要保证，走到下面的fd一定是之前用户关心过的fd
                if (!(_rfds[i].events & POLLIN))
                    continue; // 如果你没关心过读事件，那我就直接过滤你（今天我们只处理读事件，所以可以这么写）

                // 目前一定是listensock，只有这一个
                if (_rfds[i].fd == _listensock && (_rfds[i].revents & POLLIN))
                {
                    // logMessage(DEBUG, "Accepter");
                    Accepter(_listensock);
                }
                else if (_rfds[i].revents & POLLIN)
                {
                    // logMessage(DEBUG, "Recver");
                    Recver(i);
                }
                else
                {
                    // logMessage(DEBUG, "other");
                }
            }
        }
        void start()
        {
            // int timeout = 1000; // timeout内阻塞监视，timeout外非阻塞监视
            // int timeout = 0;    // 非阻塞监视
            int timeout = -1; // 阻塞式监视
            for (;;)
            {

                int n = poll(_rfds, num, timeout);
                switch (n)
                {
                case 0:
                    logMessage(NORMAL, "timeout...");
                    break;
                case -1:
                    logMessage(WARNING, "poll error, code: %d, err string: %s", errno, strerror(errno));
                    break;
                default:
                    // 说明有事件就绪了，目前只有一个监听事件就绪了
                    logMessage(NORMAL, "have event ready...");
                    HandlerReadEvent();
                    break;
                }
            }
        }
        ~pollServer()
        {
            if (_listensock >= 0)
                close(_listensock);
            if (_rfds)
                delete[] _rfds;
        }

    private:
        int _port;
        int _listensock;
        struct pollfd *_rfds;
        func_t _func;
    };
}